﻿//Copyright (C) <2013>  <jonathan cleeve norton> All Rights Reserved 
//Contact jon.norton@fin-plus.co.uk website <http://www.fin-plus.co.uk/>
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Windows.Threading;

namespace FinPlusCommon
{
    public sealed class FuncDynamics : ObservableCollection<IFinPlusFuncDynamic>, IFinPlusFuncDynamics
    {
        public event PropertyChangedEventHandler FunctionChanged, ColumnChanged;
        public override event NotifyCollectionChangedEventHandler CollectionChanged;

        private ConcurrentDictionary<string, IFinPlusFuncDynamic> index = new ConcurrentDictionary<string, IFinPlusFuncDynamic>();

        public FuncDynamics() {}

        public FuncDynamics(IFunctions funcs)
        {
            foreach (var func in funcs.Values)
                Add(new FuncDynamic(func));
        }

        //public
        public new void Add(IFinPlusFuncDynamic dynamicDict)
        {
            this.CheckReentrancy();
            base.Add(dynamicDict);
            object id = null;
            if (dynamicDict.TryGetObject("Id", out id))
                index[id.ToString()] = dynamicDict;

            dynamicDict.PropertyChanged += NotifyFunctionChanged;
            dynamicDict.PropertyColumn += NotifyColumnChanged;
        }

        public bool Remove(string id)
        {
            if (index.ContainsKey(id))
            {
                IFinPlusFuncDynamic funcDynamic = null;
                this.CheckReentrancy();
                base.Remove(index[id]);
                index.TryRemove(id.ToString(), out funcDynamic);
                return true;
            }
            return false;
        }

        public new void Clear()
        {
            base.Clear();
            index.Clear();
        }

        public void Replace(IFunctions funcs)
        {
            Clear();
            foreach (var func in funcs.Values)
                Add(new FuncDynamic(func));
        }

        public bool TryGet(string id, out IFinPlusFuncDynamic value)
        {
            return index.TryGetValue(id, out value);
        }

        public IFunctions ToFunctions()
        {
            var funcs = new Functions();
            foreach (var funcDynamic in this)
                funcs.Add(funcDynamic.ToFunction());

            return funcs;
        }

        //private
        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs a)
        { 
            using (BlockReentrancy())
            {
                var collectionChanged = this.CollectionChanged;
                if (collectionChanged == null) return;
                foreach (NotifyCollectionChangedEventHandler handler in collectionChanged.GetInvocationList())
                {
                    var dispObj = (DispatcherObject)handler.Target;
                    if (dispObj != null)
                    {
                        var disp = dispObj.Dispatcher;
                        if (disp != null && !disp.CheckAccess())
                        {
                            disp.BeginInvoke((Action)(() => handler.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))), DispatcherPriority.DataBind);
                            continue;
                        }
                    }
                    handler.Invoke(this, a);
                }
            }
        }

        private void NotifyFunctionChanged(object s, PropertyChangedEventArgs a)
        {
            if (FunctionChanged != null)
                FunctionChanged.Invoke(s, a);
        }

        private void NotifyColumnChanged(object s, PropertyChangedEventArgs a)
        {
            if (ColumnChanged != null)
                ColumnChanged.Invoke(s, a);
        }
    }
}
